﻿#region using
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using SLTimeZoneHelper.CRM2011.Enums;
using SilverCrmSoap.CrmSdk;

#endregion

namespace SLTimeZoneHelper.CRM2011
{
   /// <summary>
   ///    Usable only for CRM 2011
   /// </summary>
   public sealed class TimeZoneQueryHelper
   {
      public static QueryExpression DefaultTimeZoneQuery(int zoneCode = -1)
      {
         QueryExpression query = new QueryExpression
            {
               EntityName = typeof (timezonedefinition).Name,
               ColumnSet = new ColumnSet
                  {
                     Columns = new ObservableCollection<string>(Helper.GetEnumStrings<timezonedefinition>().ToArray())
                  },
               Distinct = true
            };
         //Enums.Helper<timezonerule>().ToArray()
         Enums.Helper.GetEnumStrings<timezonerule>().ToArray();
         FilterExpression filter = new FilterExpression();
         if (zoneCode != -1)
         {
            ConditionExpression condition = new ConditionExpression
               {
                  AttributeName = timezonedefinition.timezonecode.ToString(),
                  Operator = ConditionOperator.Equal
               };
            condition.Values.Add(zoneCode);
            filter.Conditions.Add(condition);
         }
         query.Criteria = filter;
         query.LinkEntities = new ObservableCollection<LinkEntity>
            {
               new LinkEntity
                  {
                     LinkFromEntityName = typeof (timezonedefinition).Name,
                     LinkFromAttributeName = timezonedefinition.timezonedefinitionid.ToString(),
                     LinkToEntityName = typeof (timezonerule).Name,
                     LinkToAttributeName = timezonerule.timezonedefinitionid.ToString(),
                     Columns = new ColumnSet
                        {
                           Columns = new ObservableCollection<string>(Helper.GetEnumStrings<timezonerule>().ToArray())
                        },
                     EntityAlias = typeof (timezonerule).Name,
                     JoinOperator = JoinOperator.LeftOuter
                  }
            };
         return query;
      }

      public static TimeZone ParseDefaultTimeZoneResponse(EntityCollection resp)
      {
         Entity en = resp.Entities[0];
         TimeZone zone = new TimeZone
            {
               ID = en.Id,
               Bias = en.GetAttributeValue<int>(timezonedefinition.bias.ToString()),
               StandardName = en.GetAttributeValue<string>(timezonedefinition.standardname.ToString()),
               DaylightName = en.GetAttributeValue<string>(timezonedefinition.daylightname.ToString()),
               UserInterfaceName = en.GetAttributeValue<string>(timezonedefinition.userinterfacename.ToString()),
               TimeZoneCode = en.GetAttributeValue<int>(timezonedefinition.timezonecode.ToString()),
               SchemaName = en.LogicalName
            };

         IEnumerable<TimeZoneRule> allRules = GetRules(resp.Entities.Where(x=>x.Id == en.Id));

         IEnumerable<IGrouping<DateTime, TimeZoneRule>> rulesGroupedByEffectiveDate = allRules.GroupBy(r => r.EffectiveDateTime);

         IEnumerable<TimeZoneRule> actualRules = rulesGroupedByEffectiveDate.Select(g => g.OrderByDescending(r => r.TimeZoneRuleVersionNumber).First());
         zone.TimeZoneRules = actualRules.ToList();

         return zone;
      }

      public static List<TimeZone> ParseDefaultTimeZonesResponse(EntityCollection resp)
      {
         List<TimeZone> result = new List<TimeZone>();
         foreach (var group in resp.Entities.GroupBy(x=>x.Id))
         {
            Entity en = group.First();
            TimeZone zone = new TimeZone
               {
                  ID = en.Id,
                  Bias = en.GetAttributeValue<int>(timezonedefinition.bias.ToString()),
                  StandardName = en.GetAttributeValue<string>(timezonedefinition.standardname.ToString()),
                  DaylightName = en.GetAttributeValue<string>(timezonedefinition.daylightname.ToString()),
                  UserInterfaceName = en.GetAttributeValue<string>(timezonedefinition.userinterfacename.ToString()),
                  TimeZoneCode = en.GetAttributeValue<int>(timezonedefinition.timezonecode.ToString()),
                  SchemaName = en.LogicalName
               };

            IEnumerable<TimeZoneRule> allRules = GetRules(group);

            IEnumerable<IGrouping<DateTime, TimeZoneRule>> rulesGroupedByEffectiveDate = allRules.GroupBy(r => r.EffectiveDateTime);

            IEnumerable<TimeZoneRule> actualRules = rulesGroupedByEffectiveDate.Select(g => g.OrderByDescending(r => r.TimeZoneRuleVersionNumber).First());
            zone.TimeZoneRules = actualRules.ToList();

            result.Add(zone);
         }
         return result;
      }

      private static IEnumerable<TimeZoneRule> GetRules(IEnumerable<Entity> entities)
      {
         return entities.Select(entity => new TimeZoneRule
            {
               ID = entity.Id,
               SchemaName = entity.LogicalName,
               Bias = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.bias.ToString()),
               DaylightBias = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightbias.ToString()),
               DaylightDay = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightday.ToString()),
               DaylightDayOfWeek = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightdayofweek.ToString()),
               DaylightHour = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylighthour.ToString()),
               DaylightMinute = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightminute.ToString()),
               DaylightMonth = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightmonth.ToString()),
               DaylightSecond = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightsecond.ToString()),
               DaylightYear = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.daylightyear.ToString()),
               EffectiveDateTime = entity.GetAliasedValue<DateTime>(typeof (timezonerule).Name + "." + timezonerule.effectivedatetime.ToString()),
               StandardBias = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardbias.ToString()),
               StandardDay = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardday.ToString()),
               StandardDayOfWeek = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standarddayofweek.ToString()),
               StandardHour = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardhour.ToString()),
               StandardMinute = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardminute.ToString()),
               StandardMonth = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardmonth.ToString()),
               StandardSecond = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardsecond.ToString()),
               StandardYear = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.standardyear.ToString()),
               TimeZoneDefinitionId = entity.GetAliasedValue<EntityReference>(typeof (timezonerule).Name + "." + timezonerule.timezonedefinitionid.ToString()).Id,
               TimeZoneRuleVersionNumber = entity.GetAliasedValue<int>(typeof (timezonerule).Name + "." + timezonerule.timezoneruleversionnumber.ToString())
            }).ToList();
      }
   }
}